今天要的題目是要來客製化一個影片播放器,做完之後,更加熟悉video的一些屬性跟方法,如果不是有什麼特別需求,我覺得controls (
),就很夠用了。
完成品如下:
首先都獲取我們會用到的元素
const player = document.querySelector('.player');
// 播放器
const video = player.querySelector('.viewer');
// 進度條外層
const progress = player.querySelector('.progress');
// 進度條內層
const progressBar = player.querySelector('.progress__filled');
// 播放暫停圖標
const toggle = player.querySelector('.toggle');
// 快轉倒退圖標
const skipButtons = player.querySelectorAll('.skip');
// range input
const ranges = player.querySelectorAll('.player__slider');
再來就賦予各個元素對應事件。
timeupdate
:當currentTime更新時會觸發timeupdate
事件,也就是當我們有改變影片時間軸就會觸發(如影片正在播放,進度條也會跟著改變)。
// 點選影片會進行播放或暫停
video.addEventListener('click', togglePlay);
// 點圖標會進行播放或暫停
toggle.addEventListener('click', togglePlay);
// 而在播放或暫停時候又會觸發切換按鈕圖標的函數
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
// 當currentTime更新時候觸發進度條
video.addEventListener('timeupdate', handleProgress);
// 對每個skip btn增添click事件,並呼叫skip函數
skipButtons.forEach(button => button.addEventListener('click', skip));
// 對每個range input增添change,mousemove(連續觸發)事件,並呼叫RangeUpdate函數
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
// 對進度條增添事件,可利用鼠標移動進度到指定位置。
// 判斷是否按下鼠標,預設為false
let mousedown = false;
progress.addEventListener('click', scrub);
// 當在進度條移動時,並且按下鼠標,會計算出進度條位置
progress.addEventListener('mousemove', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
而在函數部分:
播放切換,利用 video[屬性]的方式,來替代判斷式。
function togglePlay() {
// 判斷影片是否停止,如果停就播放,反之。
const method = video.paused ? 'play' : 'pause';
video[method](); // video.play() or video.pause();
// 等同於
// if(){
// video.play();
// }else{
// video.pause();
// }
}
按鈕切換
textContent
:等同於innerText
,都是獲取DOM元素內的文字內容,但建議用textContent,因為innerText 為非標準寫法,firefox並不支援
。
function updateButton() {
// 如果影片暫停了,按鈕變成►,反之。
const icon = this.paused ? '►' : '❚ ❚';
console.log(icon);
toggle.textContent = icon;
}
快轉倒退
dataset:即是以data- * 的自定義屬性
。
function skip() {
// currentTime為當前影片的時間點
// 當我按下快進25秒,利用dataset即可獲取,以data-*的自定義屬性。
// 將字串轉成float number,並return
video.currentTime += parseFloat(this.dataset.skip);
console.log(this.dataset); // DOMStringMap {skip: "25"}
}
聲音、速度控制
function handleRangeUpdate() {
// 利用[屬性]可以節省時間去寫判斷式子
// video.volume , video.playbackRate
video[this.name] = this.value;
}
進度條設置,以currentTime並以%去設置對應的進度條寬度(%)。
duration:為影片總長度。
flexBasis:為預設寬度。
function handleProgress() {
// 計算出當前時間點的百分比
const percent = (video.currentTime / video.duration) * 100;
// 將進度條的預設寬度設成百分比的寬度
progressBar.style.flexBasis = `${percent}%`;
}
進度條設置(鼠標),當點擊進度條,會根據點擊的進度條位置,去改變當前時間。
e.offsetX:為當前水平位置。
progress.offsetWidth:為進度條總長度。
function scrub(e) {
// 計算出當前進度條水平位置
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
// 更新當前影片的時間點
video.currentTime = scrubTime;
}